package com.hmy.finance.service.core.dto;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmy.finance.api.bo.core.request.ReceivableAdjustGenerateRequest;
import com.hmy.finance.api.bo.core.request.enums.FeeTypeEnum;
import com.hmy.finance.api.bo.core.request.enums.ProfitLossTypeEnum;
import com.hmy.finance.api.bo.core.response.BaseGenerateProfitLossResponse;
import com.hmy.finance.common.enums.BusinessBillTypeEnum;
import com.hmy.finance.common.enums.ProfitLossStatusEnum;
import com.hmy.finance.dal.po.DeviceRentalRecordPo;
import com.hmy.finance.dal.po.ProfitLossRecordPo;
import com.hmy.finance.service.core.dto.vos.ReceivableAdjustDetailVo;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 应收调整生成业务逻辑处理参数
 *
 * @author songkf
 */
@Data
public class ReceivableAdjustGenerateDto implements Serializable {
    private static final long serialVersionUID = 8255787968644520116L;
    /**
     * 客户ID
     */
    private Long customerId;
    /**
     * 合同ID
     */
    private Long contractId;
    /**
     * 业务单据ID
     */
    private Long businessBillId;


    /**
     * 应收调整明细集合
     */
    private List<ReceivableAdjustDetailVo> receivableAdjustDetailVoList;
    /**
     * 待处理的损益业务记录集合
     */
    private List<ProfitLossRecordPo> profitLossRecordPoList;

    /**
     * 待处理的设备租赁记录集合
     */
    private List<DeviceRentalRecordPo> deviceRentalRecordPoList;

    /**
     * 组装应收调整生成业务逻辑处理参数
     *
     * @param request 应收调整生成请求
     * @return 应收调整生成业务逻辑处理参数
     * @author songkf
     */
    public static ReceivableAdjustGenerateDto buildReceivableAdjustGenerateDto(ReceivableAdjustGenerateRequest request) {
        ReceivableAdjustGenerateDto dto = new ReceivableAdjustGenerateDto();
        dto.setCustomerId(request.getCustomerId());
        dto.setContractId(request.getContractId());
        dto.setBusinessBillId(request.getBusinessBillId());
        dto.setReceivableAdjustDetailVoList(BeanUtil.copyToList(request.getReceivableAdjustDetailVoList(), ReceivableAdjustDetailVo.class));
        return dto;
    }


    /**
     * 组装“损益业务记录”数据集合
     *
     * @param identifierGenerator 主键生成器
     * @author songkf
     */
    public void assembleProfitLossRecord(DefaultIdentifierGenerator identifierGenerator) {
        // 1.1. 组装“损益业务记录”数据集合
        this.profitLossRecordPoList = this.receivableAdjustDetailVoList.stream()
                .map(vo -> assembleProfitLossRecordPo(identifierGenerator, vo))
                .collect(Collectors.toList());

    }

    public void setDeviceRentalRecordPoList(List<DeviceRentalRecordPo> deviceRentalRecordPoList) {
        // 1.2. 修改设备租赁记录的费用周期时间
        this.deviceRentalRecordPoList = deviceRentalRecordPoList.stream()
                .peek(po -> {
                    if (po.getExpenseCycleEndTime() != null && po.getExpenseCycleEndTime().isBefore(LocalDateTime.now())) {
                        po.setExpenseCycleEndTime(LocalDateTime.now().toLocalDate().atTime(LocalTime.MAX));
                    }
                })
                .collect(Collectors.toList());
    }

    /**
     * 组装“损益业务记录”数据
     *
     * @param identifierGenerator 主键生成器
     * @param vo                  应收调整明细
     * @return 损益业务记录
     * @author songkf
     */
    private ProfitLossRecordPo assembleProfitLossRecordPo(DefaultIdentifierGenerator identifierGenerator, ReceivableAdjustDetailVo vo) {
        ProfitLossRecordPo po = new ProfitLossRecordPo();
        po.setCustomerId(this.customerId);
        po.setContractId(this.contractId);
        po.setFeeIncurredTime(LocalDateTime.now());
        po.setBusinessBillType(BusinessBillTypeEnum.RECEIVABLE_ADJUSTMENT);
        //根据vo的adjustType和profitLossType设置businessDocumentType,LOSS表示减免
        if (vo.getProfitLossType().equals(ProfitLossTypeEnum.PROFIT)) {
            switch (vo.getAdjustType()) {
                case SHIPPING:
                    po.setFeeType(FeeTypeEnum.SHIPPING_FEE);
                    break;
                case MODIFICATION:
                    po.setFeeType(FeeTypeEnum.MODIFICATION_FEE);
                    break;
                case RENT:
                    po.setFeeType(FeeTypeEnum.RENT_FEE);
                    break;
                case CLAIMS:
                    po.setFeeType(FeeTypeEnum.CLAIMS_FEE);
                    break;
            }
        } else {
            switch (vo.getAdjustType()) {
                case SHIPPING:
                    po.setFeeType(FeeTypeEnum.SHIPPING_FEE_WAIVER);
                    break;
                case MODIFICATION:
                    po.setFeeType(FeeTypeEnum.MODIFICATION_FEE_WAIVER);
                    break;
                case RENT:
                    po.setFeeType(FeeTypeEnum.RENT_FEE_WAIVER);
                    break;
                case CLAIMS:
                    po.setFeeType(FeeTypeEnum.CLAIMS_FEE_WAIVER);
                    break;
            }
        }

        po.setBusinessBillId(this.getBusinessBillId());
        po.setTotalFeeAmount(vo.getAdjustAmount());
        po.setStatus(ProfitLossStatusEnum.ALREADY_EFFECTIVE);
        po.setId(identifierGenerator.nextId(po));
        return po;
    }

    public BaseGenerateProfitLossResponse getResponse() {
        BaseGenerateProfitLossResponse response = new BaseGenerateProfitLossResponse();
        response.setResult(Boolean.TRUE);
        return response;
    }

    public Wrapper<DeviceRentalRecordPo> getDeviceRentalRecordPoListQueryWrapper() {
        return Wrappers.lambdaQuery(DeviceRentalRecordPo.class)
                .eq(DeviceRentalRecordPo::getCustomerId, this.customerId)
                .eq(DeviceRentalRecordPo::getContractId, this.contractId)
//                .isNotNull(DeviceRentalRecordPo::getExpenseCycleEndTime)
                ;
    }
}
